#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>

// 默认环形队列容量
const static int defaultcap = 5;

template<class T>
class RingQueue {
private:
    // 信号量P操作（等待）封装
    void P(sem_t &sem) {
        sem_wait(&sem);    // 信号量减1，如果为0则阻塞
    }
    // 信号量V操作（释放）封装
    void V(sem_t &sem) {
        sem_post(&sem);    // 信号量加1，唤醒等待的线程
    }
    // 加锁操作封装
    void Lock(pthread_mutex_t &mutex) {
        pthread_mutex_lock(&mutex);
    }
    // 解锁操作封装
    void Unlock(pthread_mutex_t &mutex) {
        pthread_mutex_unlock(&mutex);
    }

public:
    // 构造函数，初始化环形队列和同步原语
    RingQueue(int cap = defaultcap)
        :ringqueue_(cap),    // 初始化vector大小
         cap_(cap),          // 保存容量
         c_step_(0),         // 消费者起始位置
         p_step_(0)          // 生产者起始位置
    {
        // 初始化信号量
        sem_init(&cdata_sem_, 0, 0);     // 数据信号量，初始为0（空队列）
        sem_init(&pspace_sem_, 0, cap);  // 空间信号量，初始为容量值

        // 初始化互斥锁
        pthread_mutex_init(&c_mutex_, nullptr);  // 消费者互斥锁
        pthread_mutex_init(&p_mutex_, nullptr);  // 生产者互斥锁
    }

    // 生产者入队方法
    void Push(const T &in) {
        P(pspace_sem_);    // 等待空闲空间

        Lock(p_mutex_);    // 多个生产者间互斥
        ringqueue_[p_step_] = in;    // 放入数据
        // 环形队列位置更新
        p_step_++;
        p_step_ %= cap_;   // 保持在容量范围内循环
        Unlock(p_mutex_);

        V(cdata_sem_);     // 通知消费者有新数据
    }

    // 消费者出队方法
    void Pop(T *out) {
        P(cdata_sem_);     // 等待有数据可用

        Lock(c_mutex_);    // 多个消费者间互斥
        *out = ringqueue_[c_step_];  // 取出数据
        // 环形队列位置更新
        c_step_++;
        c_step_ %= cap_;   // 保持在容量范围内循环
        Unlock(c_mutex_);

        V(pspace_sem_);    // 通知生产者有新空间
    }

    // 析构函数，清理资源
    ~RingQueue() {
        // 销毁信号量
        sem_destroy(&cdata_sem_);
        sem_destroy(&pspace_sem_);
        // 销毁互斥锁
        pthread_mutex_destroy(&c_mutex_);
        pthread_mutex_destroy(&p_mutex_);
    }

private:
    std::vector<T> ringqueue_;   // 环形队列存储容器
    int cap_;                    // 队列容量

    int c_step_;                 // 消费者读取位置
    int p_step_;                 // 生产者写入位置

    sem_t cdata_sem_;            // 数据信号量（控制消费者）
    sem_t pspace_sem_;           // 空间信号量（控制生产者）

    pthread_mutex_t c_mutex_;    // 消费者互斥锁
    pthread_mutex_t p_mutex_;    // 生产者互斥锁
};